package com.submit.demo.util;

import com.submit.demo.config.MinIOProperties;
import com.submit.demo.model.Word;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

@Slf4j
@Component
public class MinIOUtil {
    @Autowired
    private MinIOProperties minIOProperties;

    private static MinioClient minioClient;

    /**
     * 初始化minio配置
     */
    @PostConstruct
    public void init(){
        try{

            minioClient = MinioClient.builder().endpoint(minIOProperties.getUrl())
                    .credentials(minIOProperties.getAccessKey(), minIOProperties.getSecretKey())
                    .build();

        }catch (Exception e){
            e.printStackTrace();
            log.error("初始化minio配置异常: [{}]", e.fillInStackTrace());
        }
    }

    @SneakyThrows(Exception.class)
    /**
     * 判断bucket是否存在
     */
    public static boolean isBucketExist(String bucketName){
        return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
    }


     /**
     * 创建桶
     */
     @SneakyThrows(Exception.class)
    public static void createBucket(String bucketName){
        minioClient.makeBucket(
                MakeBucketArgs.builder()
                        .bucket(bucketName)
                        .build());
    }

    /**
     * 上传文件
     */
    @SneakyThrows(Exception.class)
    public static String upload(String bucketName, String objectName, InputStream inputStream, long size){
        minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(
                inputStream, size, -1
        ).contentType("application/msword").build());
        return getImageUrl(bucketName, objectName);
    }

    /**
     * 删除文件
     */
    @SneakyThrows(Exception.class)
    public static void deleteFile(String bucketName, String objectName){
        minioClient.removeObject(RemoveObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build());
    }

    /**
     * 下载文件
     */
    @SneakyThrows(Exception.class)
    public static void download(String bucketName, String objectName, HttpServletResponse response){
        final ObjectStat stat = minioClient.statObject(StatObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build());
        response.setContentType(stat.contentType());
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(objectName, "UTF-8"));
        log.info("minio正在读取---" + objectName);
        InputStream is = minioClient.getObject(GetObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build());
        log.info("minio读取完毕");
        log.info("将文件<" + objectName + ">写入到输出流");
        IOUtils.copy(is, response.getOutputStream());
        log.info("输出完毕");
        is.close();

    }

    @SneakyThrows(Exception.class)
    public static void zipDownload(String bucketName, String[] objectNames, HttpServletResponse response){
        File zipFile = new File("/zip_temp_file");
        if(!zipFile.exists()) zipFile.createNewFile();
        ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFile));
        BufferedInputStream bf = null;
        for(String name : objectNames){
            InputStream is = minioClient.getObject(GetObjectArgs.builder()
                    .bucket(bucketName)
                    .object(name)
                    .build());
            ZipEntry zipEntry = new ZipEntry(name);
            zipOutputStream.putNextEntry(zipEntry);
            bf = new BufferedInputStream(is, 1024 * 10);
            int read = 0;
            byte[] buf = new byte[1024 * 10];
            while((read = bf.read(buf, 0, 1024 * 10)) != -1){
                zipOutputStream.write(buf, 0, read);
            }
            is.close();
        }
        if(bf != null) bf.close();
        if(zipOutputStream != null) zipOutputStream.flush();
        zipOutputStream.close();
        InputStream is = new FileInputStream(zipFile);
        minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(zipFile.getName()).stream(
                is, is.available(), -1
        ).contentType("application/x-zip-compressed").build());
        download(bucketName, zipFile.getName(), response);
        deleteFile(bucketName, zipFile.getName());
        zipFile.delete();
    }

    /**
     * 下载文件转化为byte
     */
    @SneakyThrows(Exception.class)
    public static byte[] download(String bucketName, String objectName){
        InputStream is = minioClient.getObject(GetObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build());
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int num = is.read(buffer);
            while (num != -1) {
                baos.write(buffer, 0, num);
                num = is.read(buffer);
            }
            baos.flush();
            return baos.toByteArray();
        } finally {
            if (is != null) {
                is.close();
            }
        }
    }


    /**
     * 获取minio文件的下载地址
     */
    @SneakyThrows(Exception.class)
    public static String getImageUrl(String bucketName, String objectName){
        String url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                .method(Method.POST)
                .bucket(bucketName)
                .object(objectName)
                .expiry(24 * 60 * 60)
                .build());
        return url.substring(0, url.indexOf("?"));
    }

    /**
     * 删除桶下的所有文件
     * @param bucketName 桶名
     */
    @SneakyThrows(Exception.class)
    public static void deleteAll(String bucketName){
        Iterable<Result<Item>> it = minioClient.listObjects(ListObjectsArgs.builder()
                .bucket(bucketName)
                .build());
        it.forEach(item->{
            try{
                deleteFile(bucketName,item.get().objectName());
            }catch (Exception e){
                e.printStackTrace();
            }
        });
    }

    /**
     * 批量删除文档
     */
    @SneakyThrows(Exception.class)
    public static void deleteWords(String bucketName, List<Word> list){
        List<DeleteObject> deleteObjects = new ArrayList<>(list.size());
        DeleteObject deleteObject = null;
        for (int i = 0, size = list.size(); i < size; i++) {
            deleteObject = new DeleteObject(list.get(i).getWord());
            deleteObjects.add(deleteObject);
        }
        minioClient.removeObjects(
                RemoveObjectsArgs.builder()
                        .bucket(bucketName)
                        .objects(deleteObjects)
                        .build()
        );
    }

}
